package com.wlz.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

/**
 *  配置授权服务器
 *    1. 基于内存配置
 *
 *    刷新令牌
 *      使用oauth2时，如果令牌失效了，可以使用刷新令牌通过refresh_token的授权模式再次获取access_token。只需修改认证服务器的配置，添加 refresh_token 的授权模式即可。
 *
 *      配置
 *          1.修改授权服务器配置，增加refresh_token配置
 *              .reuseRefreshTokens(false) // refresh_token是否重复使用
 *              .userDetailsService(myUserDetailsService) // 刷新令牌授权包含对用户信息的检查
 *
 *      测试（通过密码模式测试 注意：只有密码模式和授权码模式才有刷新令牌）
 *          1. 获取令牌  通过浏览器测试，需要配置支持get请求和表单验证 (浏览器地址栏输入，或者使用工具，例如 Talend API Tester )
 *                   http://localhost:8080/oauth/token?username=wlz&password=123456&grant_type=password&client_id=client&client_secret=123456&scope=all
 *              直接返回令牌 json 格式
 *
 *          2. 访问资源 （方式有多种）
 *              方式1：
 *                   http://localhost:8080/user/getCurrentUser?access_token=37b086c0-3c4e-4bfa-a200-32a08d290156
 *              方式2: (headers 里 加 Authorization ： bearer 37b086c0-3c4e-4bfa-a200-32a08d290156)
 *                  http://localhost:8080/user/getCurrentUser
 *       刷新令牌：
 *          http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123456&refresh_token=[refresh_token值]
 *          http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123456&refresh_token=de9c7723-78cb-4a01-95b5-0cc4c497e2b8
 *
 *
 *
 * @author wlz
 * @desc
 * @date 2021-10-05 14:39
 */
//@Configuration
//@EnableAuthorizationServer
public class AuthorizationServerRefreshTokenConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManagerBean;

    @Autowired
    private UserDetailsService myUserDetailsService;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManagerBean) // 使用密码模式需要配置
                .reuseRefreshTokens(false) // refresh_token是否重复使用
                .userDetailsService(myUserDetailsService) // 刷新令牌授权包含对用户信息的检查
        .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); // 支持 GET POST 请求
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients(); // 允许表单登陆
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        //刷新令牌
        //http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123456&refresh_token=de9c7723-78cb-4a01-95b5-0cc4c497e2b8

        clients.inMemory()
                .withClient("client") // 配置 client_id
                .secret(passwordEncoder.encode("123456")) // 配置 client_secret
                .accessTokenValiditySeconds(3600) // 配置访问token的有效期
                .refreshTokenValiditySeconds(864000) // 配置刷新token的有效期
                .redirectUris("https://www.baidu.com") // 配置redirect_uri，用于授权成功后跳转
                .scopes("all")  // 配置申请的权限范围
                // 配置grant_type，表示授权类型 authorization_code: 授权码模式; implicit: 简化模式; password: 密码模式; client_credentials：客户端模式；refresh_token:刷新令牌;
                .authorizedGrantTypes("authorization_code", "implicit","password","client_credentials","refresh_token");
    }
}
